package com.venusj.springbootredis.controller;

import com.venusj.springbootredis.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author venusj
 * @date 2021/3/21
 */
@RestController
@RequestMapping(value = "/good")
public class GoodController {

    private static final String GOOD_LOCK = "GOOD_LOCK";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/buy_Goods")
    public String buy_Goods() {
        String value = UUID.randomUUID().toString() + Thread.currentThread().getName();
        try {
            // setnx
//            Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(GOOD_LOCK, value);
//            stringRedisTemplate.expire(GOOD_LOCK, 10L, TimeUnit.SECONDS);
            // 变成原子性
            Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(GOOD_LOCK, value, 10L, TimeUnit.SECONDS);

            if (!flag) {
                System.out.println("加锁失败");
                return "加锁失败";
            }
            // 1.查看库存数量
            String result = stringRedisTemplate.opsForValue().get("goods:001");
            int goodsNumber = result == null ? 0 : Integer.parseInt(result);

            // 2.卖商品
            if (goodsNumber > 0) {
                int realNumber = goodsNumber - 1;
                // 3.成功买入，库存减少一件
                stringRedisTemplate.opsForValue().set("goods:001", String.valueOf(realNumber));
                System.out.println("成功买入商品，库存还剩下：" + realNumber + "服务端口：" + serverPort);
                // 4.解锁
                stringRedisTemplate.delete(GOOD_LOCK);

                return "成功买入商品，库存还剩下：" + realNumber + "服务端口：" + serverPort;
            } else {
                System.out.println("商品卖完" + "服务端口：" + serverPort);
            }
            return "商品卖完！" + "服务端口：" + serverPort;
        } finally {
            // 判断加锁与解锁是不是同一个客户端
            // 只能删除自己的key   不允许删除别人的key，还存在判断和del删除操作不是原子性的问题，可以使用lua脚本或者redis的事物解决
            if(stringRedisTemplate.opsForValue().get(GOOD_LOCK).equalsIgnoreCase(value))
            {
                // 若在此时，这把锁突然不是这个客户端的，则会误解锁
                stringRedisTemplate.delete(GOOD_LOCK);
            }

            // 方案一：使用redis事物解决
            /*while (true)
            {
                stringRedisTemplate.watch(GOOD_LOCK);
                if(stringRedisTemplate.opsForValue().get(GOOD_LOCK).equalsIgnoreCase(value))
                {
                    stringRedisTemplate.setEnableTransactionSupport(true);
                    stringRedisTemplate.multi();
                    stringRedisTemplate.delete(GOOD_LOCK);
                    List<Object> list = stringRedisTemplate.exec();
                    if (list == null) {
                        continue;
                    }
                }
                stringRedisTemplate.unwatch();
                break;
            }*/

            // 方案二：lua脚本
            /*Jedis jedis= new Jedis();
            try{
                jedis = RedisUtils.getJedis();
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                        "then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                Object eval = jedis.eval(script, Collections.singletonList(GOOD_LOCK), Collections.singletonList(value));
                if("1".equalsIgnoreCase(eval.toString()))
                {
                    System.out.println("------lua 解锁成功");
                }
                else {
                    System.out.println("------lua 解锁失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(jedis != null)
                {
                    jedis.close();
                }
            }*/

            // 还欠缺锁自动续时和集群问题 主节点数据 还未同步到slave中，就宕机了；zookeeper cp 性能没有redis好,redis是ap模式

        }
    }
}
